#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>

using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

BEGINS(test1)

template<typename T> // class T
T add (T a, T b) {
    return a + b;
}

int main() {
    cout << "add(3 + 4) = " << add(3, 4) << endl;
    cout << "add(3.1, 4.2) = " << add(3.1, 4.2) << endl; // 隐式推导
    cout << "add(3.1, 4) = " << add<double>(3.1, 4) << endl; // 显示定义
    return 0;
}

ENDS(test1)

BEGINS(test2)

template<typename T, typename U> // class T
//decltype(T() + U()) add (T a, U b) { // 如果类型没有默认构造函数就有问题
auto add(T a, U b) -> decltype(a + b) { // 返回值后置, 使用auto占位
    return a + b;
}

template<typename T>
void judge(T a) {
    cout << "unknow type" << endl;
    return ;
}

template<>
void judge(int a) {
    cout << "int type" << endl;
    return ;
}

template<>
void judge(double a) {
    cout << "double type" << endl;
    return ;
}

int main() {
    cout << "add(3 + 4) = " << add(3, 4) << endl;
    cout << "add(3.1, 4.2) = " << add(3.1, 4.2) << endl;
    cout << "add(3, 4.2) = " << add(3, 4.2) << endl;
    cout << "add(4.2, 3) = " << add(4.2, 3) << endl;
    decltype(3 + 4.2) a;
    decltype(4.2 + 3) b;
    decltype(3 + 4) c;
    decltype(string("abc") + string("def")) d;
    judge(a), judge(b), judge(c), judge(d);
//    cout << sizeof(a) << endl;
//    cout << sizeof(b) << endl;
//    cout << sizeof(c) << endl;
    return 0;
}

ENDS(test2)

BEGINS(test3)
// 模板类
template<typename T>
class PrintAny {
public:
    PrintAny(ostream &out) : out(out) {}
    PrintAny &Print(T a) {
        out << a;
        return *this;
    }
    PrintAny &endl() {
        out << std::endl;
        return *this;
    }
private:
    ostream &out;
};

int main() {
    PrintAny<int> pint(cout);
    PrintAny<double> pdouble(cout);
    PrintAny<string> pstring(cout);
    pint.Print(3).endl();
    pdouble.Print(3.1).endl();
    pstring.Print("hello world").endl();
    return 0;
}

ENDS(test3)

BEGINS(test4)
class PrintAny {
public:
    PrintAny(ostream &out) : out(out) {}
// 类中的模板函数
    template<typename T>
    PrintAny &Print(T a) {
        out << a;
        return *this;
    }
    PrintAny &endl() {
        out << std::endl;
        return *this;
    }
private:
    ostream &out;
};

int main() {
    PrintAny p(cout);
    p.Print(3).endl().Print(3.1).endl().Print("hello world").endl();
    return 0;
}

ENDS(test4)

int main() {
//    test1::main();
//    test2::main();
//    test3::main();
    test4::main();

    return 0;
}